/*
 * SelectableGroup.java  0.4.0 / Oct 26, 2010
 *
 * Copyright (c) 2010 - 2011, cute4j.com and contributors.
 *
 * This software is licensed under the LGPL version 2.1 license.
 * A copy of this license is included in the file LICENSE-LGPL.txt.
 */
package com.cute4j.swing;

import java.util.ArrayList;
import java.util.Iterator;

/**
 * Group of Selectable Objects.
 *
 * @author Slobodan Vrkacevic
 * @version 0.4.0
 */
public class SelectableGroup {

// Package-Private Fields. -----------------------------------------------------

  private final ArrayList selectables;
  private Selectable selected;

// Public Constructors. --------------------------------------------------------

  /**
   * Constructs new SelectableGroup object.
   */
  public SelectableGroup() {
    this(7);
  }

  /**
   * Constructs new SelectableGroup object.
   *
   * @param initialCapacity the initial capacity of the group
   *
   * @exception IllegalArgumentException if the initial capacity is negative
   */
  public SelectableGroup(int initialCapacity) {
    selectables = new ArrayList(initialCapacity);
  }

// Public Methods. -------------------------------------------------------------

  /**
   * Adds selectable to this group.
   *
   * @param selectable the selectable to be added
   */
  public void add(Selectable selectable) {
    if (selectable != null) {
      SelectableGroup selectableGroup = selectable.getSelectableGroup();
      if (selectableGroup != null) {
        if (selectableGroup == this) { // NOPMD
          return;
        }
        selectableGroup.remove(selectable);
      }
      if (selectable.isSelected()) {
        if (selected != null) { // NOPMD
          selected.setSelected(false);
        }
        selected = selectable;
      }
      selectables.add(selectable);
      selectable.setSelectableGroup(this);
    }
  }

  /**
   * Removes selectable from this group.
   *
   * @param selectable the selectable to be removed
   */
  public void remove(Selectable selectable) {
    if (selectable != null) {
      int selectableIndex = selectables.indexOf(selectable);
      if (selectableIndex >= 0) {
        selectable.setSelectableGroup(null);
        selectables.remove(selectable);
        if (selectable == selected) { // NOPMD
          if (selectableIndex > 0) { // NOPMD
            selected = (Selectable)selectables.get(--selectableIndex);
            selected.setSelected(true);
          } else {
            selected = null;
          }
        }
      }
    }
  }

  /**
   * Removes all selectables.
   */
  public void removeAll() {
    selected = null;
    selectables.clear();
  }

  /**
   * Returns the number of selectable objects in this group.
   *
   * @return the number of selectable objects in this group
   */
  public int getSelectableCount() {
    return selectables.size();
  }

  /**
   * Returns selectable at specified index.
   *
   * @param index the index
   *
   * @return selectable at specified index
   */
  public Selectable getSelectable(int index) {
    return (Selectable)selectables.get(index);
  }

  /**
   * Trims the capacity of group to be the same as the size of the group.
   */
  public void trimToSize() {
    selectables.trimToSize();
  }

  /**
   * Returns iterator over the selectable elements of this group.
   *
   * @return iterator over the selectable elements of this group
   */
  public Iterator getSelectables() {
    return selectables.iterator();
  }

  /**
   * Returns <tt>true</tt> if specified selectable object is member of this
   * group and it is selected; otherwise returns false.
   *
   * @param selectable the selectable object.
   *
   * @return <tt>true</tt> if specified selectable object is member of this
   *         selectable group and it is selected
   */
  public boolean isSelected(Selectable selectable) {
    return (selectable == selected); // NOPMD
  }

  /**
   * Returns selectable object.
   *
   * @return selectable object
   */
  public Selectable getSelected() {
    return selected;
  }

  /**
   * Sets selected state for the specified selectable object in the group.
   *
   * @param selectable the selectable object
   *
   * @return <tt>true</tt> if current selectable object can be deselected
   */
  public boolean setSelected(Selectable selectable) {
    if (selectable != null) {
      if (selected == selectable) { //NOPMD
        return true;
      }
      if (selectable.isSelected() && selectables.contains(selectable)) {
        if (selected != null) {
          selected.setSelected(false);
          if (selected.isSelected()) { // NOPMD
            return false;
          }
        }
        selected = selectable;
        return true;
      }
    }
    return false;
  }

}
